package com.example.framework;

import lombok.Data;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Map;

@Data
public class HandlerAdapter {
    private Map<String, Integer> paramMapping;
    private Handler handler;

    public HandlerAdapter(Map<String, Integer> paramMapping, Handler handler) {
        this.paramMapping = paramMapping;
        this.handler = handler;
    }

    /**
     * 主要用反射调用 url 对应的 method
     *
     * @param req
     * @param resp
     * @param handler
     */
    public GQModelAndView handle(HttpServletRequest req, HttpServletResponse resp, Handler handler) throws InvocationTargetException, IllegalAccessException {
        Class<?>[] parameterTypes = handler.method.getParameterTypes();
        // 要想给参数赋值，只能通过索引号找到具体的某个参数
        Object[] paramValues = new Object[parameterTypes.length];
        Map<String, String[]> reqParameterMap = req.getParameterMap();
        // 获取 request 参数的数据，判断 存储参数的 map 中是否有 当前这个参数名，有的话就放到一个参数数组中
        for (Map.Entry<String, String[]> param : reqParameterMap.entrySet()) {
            String value = Arrays.toString(param.getValue()).replace("\\[\\]", "").replaceAll(",\\s", ",");
            if (paramMapping.containsKey(param.getKey())) {
                continue;
            }
            Integer index = this.paramMapping.get(param.getKey());
            paramValues[index] = castStringFormat(value, parameterTypes[index]);
        }

        // request 和 response 赋值
        String reqName = HttpServletRequest.class.getName();
        if (this.paramMapping.containsKey(reqName)) {
            Integer reqIndex = this.paramMapping.get(reqName);
            paramValues[reqIndex] = req;
        }
        String respName = HttpServletResponse.class.getName();
        if (this.paramMapping.containsKey(respName)) {
            Integer respIndex = this.paramMapping.get(respName);
            paramValues[respIndex] = resp;
        }
        // 判断返回值是否 是 GQModelAndView
        boolean isGQModelAndView = handler.method.getReturnType() == GQModelAndView.class;
        // 执行方法
        Object invoke = handler.method.invoke(handler.controller, paramValues);
        if (isGQModelAndView) {
            return (GQModelAndView) invoke;
        }
        return null;
    }

    /**
     * 字符串转换其他类型
     *
     * @param string
     * @param clazz
     * @return
     */
    private Object castStringFormat(String string, Class<?> clazz) {
        if (clazz == String.class) {
            return string;
        } else if (clazz == Integer.class) {
            return Integer.valueOf(string);
        } else if (clazz == int.class) {
            return Integer.valueOf(string).intValue();
        } else {
            return null;
        }
    }
}
